/*
 * 功能：消息通知服务类，提供消息通知相关的业务逻辑操作
 * 作者：张杨(Sunny)
 * 日期： 2024/11/30 下午2:44
 */
package com.example.springboot.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springboot.common.Result;
import com.example.springboot.entity.Message;
import com.example.springboot.entity.User;
import com.example.springboot.mapper.MessageMapper;
import com.example.springboot.mapper.UserMapper;
import com.example.springboot.utils.TokenUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service
public class MessageService extends ServiceImpl<MessageMapper, Message> {

    @Resource
    MessageMapper messageMapper;

    @Resource
    UserMapper userMapper;


    /**
     * 分页查询消息，支持按内容、状态、用户名和是否已读进行筛选
     *
     * @param pageNum  当前页码
     * @param pageSize 每页显示的记录数
     * @param content  内容（模糊查询）
     * @param state    状态（模糊查询）
     * @param username 用户名（精确查询）
     * @param isRead   是否已读（模糊查询）
     * @return 返回分页查询结果
     */
    public Page<Message> selectByPage(Integer pageNum, Integer pageSize, String content, String state, String username, String isRead) {
        QueryWrapper<Message> queryWrapper = new QueryWrapper<Message>().orderByAsc("isRead");
        queryWrapper.like(StrUtil.isNotBlank(content), "content", content);
        queryWrapper.eq(StrUtil.isNotBlank(username), "username", username);
        queryWrapper.like(StrUtil.isNotBlank(state), "state", state);
        queryWrapper.like(StrUtil.isNotBlank(isRead), "isRead", isRead);
        return messageMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper);
    }


    /**
     * 将当前用户的所有未读消息标记为已读。
     *
     * @return 操作结果
     */
    public Result markAllAsRead() {
        User currentUser = TokenUtils.getCurrentUser();  // 获取到当前登录的用户信息
        if (currentUser == null) {
            // 如果当前用户为空，返回错误结果
            return Result.error("用户未登录");
        }
        QueryWrapper<Message> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", currentUser.getUsername()).eq("isRead", "0");
        // 创建一个 Message 对象用于更新
        Message updateInfo = new Message();
        updateInfo.setIsRead("1");
        // 使用 messageMapper 的 update 方法来更新符合条件的记录
        int updatedRows = messageMapper.update(updateInfo, queryWrapper);
        if (updatedRows > 0) {
            // 如果有记录被更新，返回成功结果
            return Result.success();
        } else {
            // 如果没有记录被更新，返回错误结果
            return Result.error("没有未读消息");
        }
    }


    /**
     * 计算每个用户的未读消息数量，并更新用户表中的未读消息计数。
     *
     * @return 返回一个Map，包含处理过的用户数量。
     */
    @Transactional
    public Map<String, Integer> unReadCountPerUser() {
        // 创建查询包装器，用于构建查询未读消息的SQL语句
        QueryWrapper<Message> queryWrapper = new QueryWrapper<>();
        // 查询所有不同的用户名
        queryWrapper.select("DISTINCT username");
        // 执行查询并获取结果列表
        List<Map<String, Object>> resultList = messageMapper.selectMaps(queryWrapper);
        // 创建更新包装器，用于构建更新用户未读消息计数的SQL语句
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();

        // 遍历每个用户，计算未读消息数量并更新
        for (Map<String, Object> result : resultList) {
            String username = (String) result.get("username");
            // 获取指定用户的总消息数量
            int messagesPerUserCount = getMessagesPerUser(username);
            // 获取指定用户已读消息数量
            int messagesPerUserCountEq1 = getMessagesPerUserEq1(username);
            // 计算未读消息数量
            String count = String.valueOf(messagesPerUserCount - messagesPerUserCountEq1);
            // 设置更新条件为特定用户名，并更新未读消息计数
            updateWrapper.eq("username", username).set("unRead", count);
            // 执行更新操作
            userMapper.update(null, updateWrapper);
            // 清空UpdateWrapper对象，以便下一次循环使用
            updateWrapper.clear();
        }
        // 创建一个新的HashMap对象，并添加一个键值对，键为"handlerCount"，值为resultList的大小，然后返回这个Map
        return new HashMap<String, Integer>() {{
            put("handlerCount", resultList.size());
        }};
    }

    // 获取指定用户的消息数量
    public int getMessagesPerUser(String username) {
        // 创建一个查询包装器，用于构建SQL查询语句
        QueryWrapper<Message> queryWrapper = new QueryWrapper<>();
        // 设置查询条件，匹配用户名，并且只选择计数函数的结果
        queryWrapper.eq("username", username).select("COUNT(*)");
        // 执行查询并获取结果列表
        List<Object> totalCountList = messageMapper.selectObjs(queryWrapper);
        // 如果结果列表为空，则返回0，否则将结果转换为整数并返回
        return totalCountList.isEmpty() ? 0 : ((Number) totalCountList.get(0)).intValue();
    }

    // 获取指定用户已读消息的数量
    public int getMessagesPerUserEq1(String username) {
        // 创建查询包装器，用于构建数据库查询条件
        QueryWrapper<Message> queryWrapper = new QueryWrapper<>();
        // 设置查询条件，匹配用户名且消息状态为已读
        queryWrapper.eq("username", username).eq("isRead", "1");
        // 指定查询结果只返回记录的数量，而不是具体的记录信息
        queryWrapper.select("COUNT(*)");
        // 执行查询并获取总数，selectObjs方法返回一个包含单个元素的列表，该元素是查询结果的总行数
        List<Object> totalCountList = messageMapper.selectObjs(queryWrapper);
        // 如果列表为空，则总数为0；否则，将列表中的第一个元素转换为整数类型作为总数
        // 返回查询到的已读消息总数
        return totalCountList.isEmpty() ? 0 : ((Number) totalCountList.get(0)).intValue();
    }

}
